﻿using Soft.Data;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Soft.Service
{
    /// <summary>
    /// 远程控制命令拦截器
    /// </summary>
    public sealed class RemoteControlCommandInterpreter : SoftObject, IDisposable
    {
        public RemoteControlCommandInterpreter()
        {
            this.mHeartbeatSignal = new RemoteControlCommandInterpreter.HeartbeatSignal();
            this.ConnectedMappings = new List<ConnectedMappingInfo>();

            ///监控心跳信号定时器
            this.mMonitorHeartbeatSignalTimer = new Timer(1000.0);
            //
            this.mMonitorHeartbeatSignalTimer.Elapsed += delegate (object s, ElapsedEventArgs e)
            {
                //如果心跳信号消失高于5秒,则设置心跳连接状态为false，并发出心跳消失通知
                if (this.mHeartbeatSignal.Interval > 5L)
                {
                    if (this.mHeartbeatSignalConnectState)
                    {
                        this.mHeartbeatSignalConnectState = false;
                        HeartbeatDisappearEventHandle heartbeatDisappear = this.HeartbeatDisappear;
                        if (heartbeatDisappear != null)
                        {
                            heartbeatDisappear();
                        }
                    }
                }
                else if (!this.mHeartbeatSignalConnectState)
                {
                    this.mHeartbeatSignalConnectState = true;
                    HeartbeatRecoverEventHandle heartbeatRecover = this.HeartbeatRecover;
                    if (heartbeatRecover != null)
                    {
                        heartbeatRecover();
                    }
                }
                if (this.ConnectedMappings.Count > 0)
                {
                    List<ConnectedMappingInfo> connectedMappings = this.ConnectedMappings;
                    lock (connectedMappings)
                    {
                        for (int i = this.ConnectedMappings.Count - 1; i >= 0; i--)
                        {
                            if (this.ConnectedMappings[i].Disconnected)
                            {
                                this.ConnectedMappings.RemoveAt(i);
                            }
                        }
                    }
                }
            };
        }

        ~RemoteControlCommandInterpreter()
        {
            this.Dispose();
        }


        /// <summary>
        /// 心跳信号消失时 发出的事件通知     （开启广播）
        /// </summary>
        public event HeartbeatDisappearEventHandle HeartbeatDisappear;


        /// <summary>
        /// 心跳信号恢复时，发出的事件通知    （关闭广播）
        /// </summary>
        public event HeartbeatRecoverEventHandle HeartbeatRecover;


        /// <summary>
        /// 连接信息
        /// </summary>
        internal List<ConnectedMappingInfo> ConnectedMappings { get; private set; }

    
        public void Start()
        {
            this.mMonitorHeartbeatSignalTimer.Start();
        }


        public void Stop()
        {
            this.mMonitorHeartbeatSignalTimer.Stop();
        }


        public void Add(string functionCode, Type processorType, string explain, params object[] constructorParameters)
        {
            if (string.IsNullOrWhiteSpace(functionCode))
            {
                throw new ArgumentNullException("controlCommand");
            }
            functionCode = functionCode.Trim().ToUpper();
            if (this.List.ContainsKey(functionCode))
            {
                throw new Exception("The '" + functionCode + "' function code interpreter has existed");
            }
            RemoteControlCommandInterpreter.ProcessorInfo processorInfo = new RemoteControlCommandInterpreter.ProcessorInfo();
            if (processorType == null)
            {
                throw new ArgumentNullException("processorType");
            }
            processorInfo.ProcessorType = processorType;
            processorInfo.ConstructorParameters = constructorParameters;
            processorInfo.Explain = explain;
            RemoteControlCommandInterpreter.ProcessorInfo value = processorInfo;
            this.List.Add(functionCode, value);
        }


        public ResultJson Execute(CallMethodInstruction callMethodInstruction)
        {
            ResultJson resultJson = new ResultJson();
            if (this.List.ContainsKey(callMethodInstruction.FunctionCode))
            {
                if (callMethodInstruction.FunctionCode == RemoteControlCode.Heartbeat.Code)
                {
                    this.mHeartbeatSignal.Reset();
                    Task.Run(delegate ()
                    {
                        this.AddMappingInfo(callMethodInstruction.ClientIPAddress);
                    });
                }
                try
                {
                    RemoteControlCommandInterpreter.ProcessorInfo processorInfo = this.List[callMethodInstruction.FunctionCode];
                    BaseRemoteControlProcessor baseRemoteControlProcessor;
                    if (processorInfo.ConstructorParameters == null)
                    {
                        baseRemoteControlProcessor = (BaseRemoteControlProcessor)Activator.CreateInstance(processorInfo.ProcessorType);
                    }
                    else
                    {
                        baseRemoteControlProcessor = (BaseRemoteControlProcessor)Activator.CreateInstance(processorInfo.ProcessorType, processorInfo.ConstructorParameters);
                    }
                    return baseRemoteControlProcessor.Processing(callMethodInstruction.JsonParams);
                }
                catch (Exception exception)
                {
                    resultJson.AddError(exception, null);
                    return resultJson;
                }
            }
            resultJson.AddError("The '" + callMethodInstruction.FunctionCode + "' function code is not a system control code.", null);
            return resultJson;
        }


        public void Dispose()
        {
            this.mMonitorHeartbeatSignalTimer.Stop();
        }

        private void AddMappingInfo(IPAddress ip)
        {
            List<ConnectedMappingInfo> connectedMappings = this.ConnectedMappings;
            lock (connectedMappings)
            {
                ConnectedMappingInfo connectedMappingInfo = this.ConnectedMappings.Find((ConnectedMappingInfo e) => e.IPAddress.Equals(ip));
                if (connectedMappingInfo == null)
                {
                    try
                    {
                        ConnectedMappingInfo item = new ConnectedMappingInfo(ip);
                        this.ConnectedMappings.Add(item);
                        return;
                    }
                    catch
                    {
                        return;
                    }
                }
                connectedMappingInfo.ResetTicks();
            }
        }


        private const long HEARTBEAT_DISAPPEAR_INTERVAL_SECONDS = 5L;


        private const double HEARTBEAT_DETECTION_INTERVAL_MILLISECONDS = 1000.0;


        private Timer mMonitorHeartbeatSignalTimer;


        private RemoteControlCommandInterpreter.HeartbeatSignal mHeartbeatSignal;


        private bool mHeartbeatSignalConnectState = true;


        private SortedList<string, RemoteControlCommandInterpreter.ProcessorInfo> List = new SortedList<string, RemoteControlCommandInterpreter.ProcessorInfo>();


        private class ProcessorInfo
        {
   
            public Type ProcessorType;

       
            public object[] ConstructorParameters;


            public string Explain;
        }


        /// <summary>
        /// 心跳信号
        /// </summary>
        private class HeartbeatSignal
        {
            ~HeartbeatSignal()
            {
                this.mStopwatch.Stop();
            }

            /// <summary>
            /// 重置心跳信号计时器
            /// </summary>
            public void Reset()
            {
                if (this.mStopwatch.IsRunning)
                {
                    this.mStopwatch.Restart();
                    return;
                }
                this.mStopwatch.Start();
            }


            /// <summary>
            /// 心跳已经执行的时长
            /// </summary>
            public long Interval
            {
                get
                {
                    if (this.mStopwatch.IsRunning)
                    {
                        return this.mStopwatch.ElapsedMilliseconds / 1000L;
                    }
                    return long.MaxValue;
                }
            }

     
            private Stopwatch mStopwatch = new Stopwatch();
        }
    }

}
